/*
 * ExtensibleHashIndexStratregy.h
 *
 *  Created on: 03/10/2009
 *      Author: nik0l4z
 */

#ifndef EXTENSIBLEHASHINDEXSTRATREGY_H_
#define EXTENSIBLEHASHINDEXSTRATREGY_H_


#include "../Strategies/Resource/ResourceStrategy.h"
#include "ArchivoTexto.h"
#include "math.h"
#include <list>
#include "../Hash/Tabladirecciones.h"
#include "../Externa/Clave.h"
#include "Bloque.h"
#include "Registro.h"
#include "IndexStrategy.h"
#include "BloqueHashDisco.h"
#include "StorageResource.h"
#include "../Strategies/Storage/BlockStorageStrategy.h"
#include "../Hash/TablaTamanioDisp.h"
#include "../Externa/Dato.h"
#include <vector>
#include <sstream>
#include <math.h>




class ExtensibleHashIndexStratregy : public IndexStrategy{

	private: int ultimonrobloque;

	private: Tabladirecciones *tabla;

	private: int tamanioCubo;

	private: string nombrearchivo;

	private:  ArchivoTexto *arch;

	TablaTamanioDisp *TablaDisp;

	public: vector <int> NroCubosDisponibles;

	private: BlockStorageStrategy *Blockstorage;



	//StorageResource * resource = StorageResource::getInstance();



	public:ExtensibleHashIndexStratregy();

	/* ExtensibleHashIndexStratregy(int tamaniocub, const string& nombrearchivo);
	 *
	 * Creacion del indice. Recibe el tamanio del bloque y el nombre del archivo de datos.
	 *
	 * */

	public:ExtensibleHashIndexStratregy(int tamaniocub, const string& nombrearchivo, StorageStrategy *storage);

	virtual ~ExtensibleHashIndexStratregy();


	/*---------------Metodos publicos que implementan la interfaz-------------------------------*/
	public: virtual  bool checkUniqueness(Clave *clave, Dato *dato);

	public: virtual  void updateIndex(int fileReference,Clave *clave,Dato *dato);

	/**
	 * Metodo que, apartir de una clave, devuelve la posicion en la que se
	 * encuentra el dato correspondiente a esa clave, en el hash
	 * En caso de no encontrarla, devuelve un valor negativo.
	 */
	public: virtual int getStorageReferenceByKey(Clave *clave);

	/**
	 * Metodo que borra la clave del indice actualizandolo.Devuelve un numero negativo en caso de error.
	 */
	public: virtual int deleteKey(Clave *clave);

	/*--------------------------------------------------------------------------------------------------*/



	private: virtual void saludar();



	// Funcion que recibe una clave
	// y calcula en que posicion de la tabla de direcciones se encuentra el numero de bloque donde se encuentra o insertara la clave

	private: virtual int funcionhash(Clave clave);


	// Recibe una posicion de la tabla de direcciones
	// Busca que numero de bloque se encuentra en dicha posicion.

	private: virtual  int buscar(unsigned int posiciontabla);


	// Recibe un numero de bloque
	// Invoca a una estrategia de almacenamiento para leer el bloque en cuestion
	// Devuelve el bloque leido

	private: virtual  Bloque *leercubo(int nrocubo);


	// Recibe un numero de bloque y un bloque
	// Invoca a una estrategia de almacenamiento para escribir el bloque en cuestion
	// Devuelve un entero indicando el resultado

	private: virtual  int escribircubo(Bloque cubo, int nrocubo);

	/*Metodo que recibe una clave y un cubo.
	 * Busca si la clave coincide con la clave de alguno de los registros del cubo
	 * Si encuentra la clave devuelve 0
	 * Si no la encuentra devuelve 1
	 */

	private: virtual  int verificarunicidad(Bloque cubo,Clave clave);


	/* Metodo que recibe dos punteros a cubos, un registro y el tamanio del mismo.
	 * Se encarga de quitar todos los registros del cubo "cubo", y aplica la funcion Hash para cada uno de ellos.
	 * Todos los registros se repartiran entre el cubo "cubo" y el cubo "cuboaux"
	 * Luego aplica la funcion hash para el registro recibido.
	 * Verifica en cual de ambos cubos recibidos debe ir dicho registro.
	 * Entonces graba el cubo que ya no se utilizara, e invoca al metodo insercion, para que intente colocar el registro en el cubo restante
	 */

	private: virtual  void RepartirClaves(Bloque *cubo,Bloque *cuboaux,Registro reg, int tamanioreg);


	/*
	 * Metodo que agrega el registro "reg" al cubo.
	 * Ademas actualiza el espacio libre del cubo, restandole el tamanioreg
	 *
	 */
	private: virtual  void AgregarRegABloque(Registro reg, Bloque *cubo, int tamanioreg);

	/*
	 * Metodo que quita el registro "reg" al cubo.
	 * Ademas actualiza el espacio libre del cubo, sumandole el tamanioreg
	 *
	 */
	private: virtual  int QuitarRegABloque(Clave clave, Bloque *cubo, int tamanioreg);

	/* Metodo que modifica la posicion de la tabla de direcciones "posicion" colocando en ella ultimnrobloque
	 * Ademas recorre la tabla avanzando a "tamaniodispCubo" posiciones, modificandolas con el ultimonrobloque
	 *
	 */
	private: virtual  int ActualizarTabla(int tamaniodispCubo, int posicion,int ultimonrobloque);


	/* Metodo que inserta un registro en un bloque (cuyo numero se encuentra en la posicion "posicion" de la tabla de direcciones)
	 * Primero verifica si hay espacio suficiente para el nuevo registro en el cubo
	 * Si lo hubiera  agrega el registro y graba el cubo
	 * Si no lo hubiera actualiza la tabla de direcciones o al duplica y actualiza segun corresponda
	 * Luego Invoca a Repartir Claves
	 */
	private: virtual  int Insercion(Bloque *cubo, Registro reg, int posicion);

	/* Metodo que elimina el registro con clave "clave" del cubo correspondiente.
	 * Devuelve -1 en caso de que halla habido un error al eliminar
	 * De lo contrario devuelve 0
	 *
	 */
	private: virtual  int Eliminar(Clave clave);

	/* Funcion que levanta de archivo la metada necearia para el indice hash
	 * Nro de ultimo bloque grabado y bloques libres.
	 */
	private: virtual  void Deserealizar();

	/*	Funcion que graba en archivo la metadata necesaria para el indice hash
	 * La serializacion se realiza de la siguiente forma:
	 *
	 * <UltimoNrodeBloqueGrabado> / <BloqueLibre1> % <BloqueLibre2> %... <BloqueLibreN>.
	 *
	 */
	private: virtual  void Serializar();

	/*	Metodo que devuelve el proximo nro de bloque a utilizar.
	 * Esta funcion se utiliza para reutilizar los bloques libres
	 *
	 */
	private: virtual int ObtenerProxNumeroBloque();

	/*Funcin que recibe un dato y una clave.
	 * Busca el bloque que contiene el registro con dicha clave.
	 * Lo quita de dicho bloque. y luego llama a Insertar el registro modificado.
	 * Devuelve -1 en caso de que hubiera habido un error al modificar el dato.
	 * */
	private: virtual int Modificar(Clave clave, Dato *dato);

	/**
	 * Workaround agregado, dado que las distintas estrategias de indexado comparten una misma interfaz, y su comportamiento no se el mismo
	 * Problema de Arquitectura.
	 */
	virtual int getClassName();

	public: virtual Almacenamiento * getStorage() const;

	public: virtual void setStorage(Almacenamiento *storage);


};

#endif /* EXTENSIBLEHASHINDEXSTRATREGY_H_ */
